
package andre.grids.network;

import com.db4o.*;
import andre.grids.db.*;
import andre.grids.db.dataclasses.*;

import andre.grids.filesystem.server.configuration.ConfigurationManager;
import andre.grids.filesystem.server.configuration.RmiRegister;
import java.rmi.RemoteException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Vector;

/**
 *
 * @author andre
 */
public class MasterPeerTable {
    private Hashtable<String, PeerObjects> peers;
    
    public MasterPeerTable() { 
        peers = new Hashtable<String, PeerObjects>(200);        
        loadPeersFromDb();
        updateDbWithList(ConfigurationManager.getDirMasterList());
    }
    
    public void addPeer(String hostName)
    {
        if (peers.containsKey(hostName))
        {
            try
            {
                PeerObjects objs = peers.get(hostName);
                objs.release();
                objs = new PeerObjects(hostName);
                peers.remove(hostName);                
                peers.put(hostName, objs);
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, this);
                return;
            }
        }
        else // nunca foi adicionado à tabela, portanto deve ir para o banco de dados
        {
            DbPeer peer = new DbPeer();
            peer.setPeerName(hostName);
            peer.setDirectoryMaster(true);
            PeerObjects objs = null;
            try
            {
                objs = new PeerObjects(peer.getPeerName());            
            }
            catch(Exception e)
            {
                andre.grids.util.log.Log.logException(e, peer);
                return;
            }
            Database db = Database.getGridFsDb();
            db.storeObjectTree(peer);
            peers.put(peer.getPeerName(), new PeerObjects(peer.getPeerName()));
        }
    }
    
    public PeerObjects getObjectsFor(String hostName) throws RemoteException
    {
        if (!peers.containsKey(hostName))
            return null;
        PeerObjects objs = peers.get(hostName);
        if (objs == null)
        {
            objs = new PeerObjects(hostName);
            peers.put(hostName, objs);
            return objs;
        }
        return peers.get(hostName);
    }
    
    public Enumeration<PeerObjects> getAllObjects()
    {
        Enumeration<String> hosts = peers.keys();
        
        // este trecho do codigo inicializa todos os 
        // objetos armazenados na tabela
        while(hosts.hasMoreElements()) {
            try {
                String host;
                host = hosts.nextElement();
                getObjectsFor(host);
            } catch(Exception e) {
                andre.grids.util.log.Log.logException(e, this);
            }
        }
        
        return peers.elements();
    }
    
    public Enumeration<PeerObjects> getAllRemoteObjects()
    {
        Vector<PeerObjects> objs =new Vector<PeerObjects>(peers.size() - 1);
        Enumeration<PeerObjects> all = getAllObjects();
        while(all.hasMoreElements())
        {
            PeerObjects obj = all.nextElement();
            if (obj.isLocal()) {
                continue; // se for um objeto local pula para o próximo
            }
            else {
                objs.add(obj);                
            }
        }
        return objs.elements();
    }
    
    public boolean containsPeer(String peerName)
    {
        return peers.containsKey(peerName);
    }
    
    private void loadPeersFromDb()
    {
        Database db = Database.getGridFsDb();
        DbPeerQueries query = new DbPeerQueries();
        Vector<DbPeer> list = query.getDirectoryMasters();
        Iterator<DbPeer> it = list.iterator();
        for(;it.hasNext();)
        {
            DbPeer peer;
            peer = it.next();
            peers.put(peer.getPeerName(), new PeerObjects(peer.getPeerName()));
        }
    }
    
    private void updateDbWithList(String[] peersArray) {
        Database db = Database.getGridFsDb();
        DbPeerQueries query = new DbPeerQueries();
        Vector<DbPeer> list = query.getDirectoryMasters();
        String [] alreadyInDb = new String[list.size()];
        for(int i = 0; i < alreadyInDb.length; i++)
            alreadyInDb[i] = list.get(i).getPeerName();
        java.util.Arrays.sort(alreadyInDb);
        for(int i = 0; i < peersArray.length; i++)
        {
            if (java.util.Arrays.binarySearch(alreadyInDb, peersArray[i]) == -1)
            {
                DbPeer peer;
                peer = new DbPeer();
                peer.setDirectoryMaster(true);
                peer.setPeerName(peersArray[i]);
                db.storeObjectTree(peer);
            }
        }
        loadPeersFromDb();
    }
    
    private static MasterPeerTable instance;
    public static MasterPeerTable getInstance() {
        if (instance == null)
            instance = new MasterPeerTable();
        return instance;
    }
}
